package com.rla.common.utils;

import cn.hutool.core.date.DateUtil;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.http.HttpMethodName;
import com.qcloud.cos.model.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Date;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import com.qcloud.cos.utils.IOUtils;
import com.rla.common.config.CosClientConfig;
import com.rla.common.utils.file.FileUploadUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.file.Files;
import java.nio.file.Path;

/**
 * Cos 对象存储操作
 */
@Component
public class CosManager {

    @Resource
    private CosClientConfig cosClientConfig;

    @Resource
    private COSClient cosClient;

    private static final Logger logger = LoggerFactory.getLogger(CosManager.class);

    /**
     * 上传对象
     * @param key 唯一键
     * @param localFilePath 本地文件路径
     * @return 上传结果
     */
    public PutObjectResult putObject(String key, String localFilePath) {
        PutObjectRequest putObjectRequest = new PutObjectRequest(cosClientConfig.getBucket(), key, new File(localFilePath));
        return cosClient.putObject(putObjectRequest);
    }

    /**
     * 上传对象
     * @param key 唯一键
     * @param file 文件
     * @return 上传结果
     */
    public PutObjectResult putObject(String key, File file) {
        PutObjectRequest putObjectRequest = new PutObjectRequest(cosClientConfig.getBucket(), key, file);
        return cosClient.putObject(putObjectRequest);
    }

    /**
     * 下载对象（没有过期时间）
     * @param key 唯一键
     * @return COSObject
     */
    public COSObject getObject(String key) {
        GetObjectRequest getObjectRequest = new GetObjectRequest(cosClientConfig.getBucket(), key);
        return cosClient.getObject(getObjectRequest);
    }

    /**
     * 生成下载链接
     * @param key 唯一键
     * @param expiration 下载链接过期时间
     * @return 生成的下载链接
     */
    public String generatePresignedUrl(String key, Date expiration) {
        GeneratePresignedUrlRequest generatePresignedUrlRequest =
                new GeneratePresignedUrlRequest(cosClientConfig.getBucket(), key, HttpMethodName.GET)
                        .withMethod(HttpMethodName.GET)
                        .withExpiration(expiration);
        URL url = cosClient.generatePresignedUrl(generatePresignedUrlRequest);
        return url.toString();
    }

    /**
     * 上传文件到 COS
     * @param multipartFile 上传的文件
     * @return 文件路径
     */
    public ResponseEntity<String> uploadFile(@RequestPart("file") MultipartFile multipartFile) {
        /* 文件目录 */
        String filename = multipartFile.getOriginalFilename();
        String filepath = "/XCX/"+FileUploadUtils.extractFilename(multipartFile);
//        String path= "/XCX/"+ DateUtil.year(new Date())+"/"+DateUtil.month(new Date())+"/%s";
//        String filepath = String.format(path, filename);
        Path tempFilePath = null;
        try {
            /* 创建临时文件 */
            tempFilePath = Files.createTempFile("temp_", "_" + filename);
            multipartFile.transferTo(tempFilePath.toFile());
            /* 上传文件 */
            putObject(filepath, tempFilePath.toFile());
            /* 返回文件路径 */
            return ResponseEntity.ok(cosClientConfig.getCosHost()+filepath);
        } catch (IOException ioException) {
            logger.error("File IO error, filepath = {}", filepath, ioException);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("File upload failed due to IO error.");
        } catch (Exception e) {
            logger.error("File upload error, filepath = {}", filepath, e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("File upload failed.");
        } finally {
            if (tempFilePath != null) {
                try {
                    /* 删除临时文件 */
                    Files.delete(tempFilePath);
                } catch (IOException e) {
                    logger.error("File delete error, filepath = {}", filepath, e);
                }
            }
        }
    }

    /**
     * 通过预签名 URL 下载文件(有过期时间)
     * @param filepath 文件路径
     * @param response HttpServletResponse
     * @throws IOException IO 异常
     */
    public void downloadFile(String filepath, HttpServletResponse response) throws IOException {
        try {
            /* 生成私有下载链接 */
            Date expiration = new Date(System.currentTimeMillis() + Long.parseLong(cosClientConfig.getExpireTime()));
            String presignedUrl = generatePresignedUrl(filepath, expiration);

            /* 使用预签名 URL 下载文件 */
            URL url = new URL(presignedUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");

            /* 处理连接响应 */
            try (InputStream inputStream = connection.getInputStream()) {
                byte[] bytes = IOUtils.toByteArray(inputStream);

                /* 设置响应头 */
                response.setContentType(cosClientConfig.getCosHostHeader());
                String encodedFilename = URLEncoder.encode(filepath, "UTF-8").replaceAll("\\+", "%20");
                response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFilename + "\"");

                /* 写入响应输出流 */
                response.getOutputStream().write(bytes);
                response.getOutputStream().flush();
            }
        } catch (IOException e) {
            logger.error("File download error, filepath = {}", filepath, e);
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "File download failed.");
        }
    }

    /**
     * 直接从 COS 下载文件（无过期时间）
     * @param filepath 文件路径
     * @param response HttpServletResponse
     * @throws IOException IO 异常
     */
    public void downloadFileDirect(String filepath, HttpServletResponse response) throws IOException {
        COSObjectInputStream cosObjectInput = null;
        try {
            /* 获取 COS 对象 */
            COSObject cosObject = getObject(filepath);
            cosObjectInput = cosObject.getObjectContent();

            /* 将 COS 对象内容转换为字节数组 */
            byte[] bytes = IOUtils.toByteArray(cosObjectInput);

            /* 设置响应头 */
            response.setContentType(cosClientConfig.getCosHostHeader());
            String encodedFilename = URLEncoder.encode(filepath, "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFilename + "\"");

            /* 写入响应输出流 */
            response.getOutputStream().write(bytes);
            response.getOutputStream().flush();
        } catch (Exception e) {
            logger.error("File download error, filepath = {}", filepath, e);
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "File download failed.");
        } finally {
            /* 确保输入流关闭 */
            if (cosObjectInput != null) {
                try {
                    cosObjectInput.close();
                } catch (IOException e) {
                    logger.error("Error closing COSObjectInputStream", e);
                }
            }
        }
    }

    /**
     * 获取文件下载链接 （有过期时间）
     * @param filepath 文件路径
     * @return 文件的下载链接
     */
    public ResponseEntity<String> getFileDownloadLink(String filepath) {
        try {
            /* 生成私有下载链接（有效期根据配置） */
            Date expiration = new Date(System.currentTimeMillis() + Long.parseLong(cosClientConfig.getExpireTime()));
            String presignedUrl = generatePresignedUrl(filepath, expiration);

            /* 返回下载链接 */
            return ResponseEntity.ok(presignedUrl);
        } catch (Exception e) {
            logger.error("Error generating download link for filepath = {}", filepath, e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Failed to generate download link.");
        }
    }
}